////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2017-2018 Qualcomm Technologies, Inc.
// All Rights Reserved.
// Confidential and Proprietary - Qualcomm Technologies, Inc.
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// @file  camxhaldevice.cpp
/// @brief Definitions for HALDevice class
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

#include "camxchitypes.h"
#include "camxchi.h"
#include "camxdebug.h"
#include "camxhal3entry.h"  /// @todo (CAMX-351) Remove this header
#include "camxhal3metadatautil.h"
#include "camxhal3module.h"
#include "camxhaldevice.h"
#include "camxhwcontext.h"
#include "camxhwfactory.h"
#include "camxmem.h"
#include "camxmemspy.h"
#include "camxosutils.h"
#include "camxpipeline.h"
#include "camxsession.h"
#include "camxtrace.h"
#include "camxsensornode.h"

#include "chioverride.h"

CAMX_NAMESPACE_BEGIN

// Forward declaration
struct SubDeviceProperty;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Constants
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
static const BOOL AllowStreamReuse = FALSE;         ///< Flag used to enable stream reuse

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// HALDevice::~HALDevice
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
HALDevice::~HALDevice()
{
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// HALDevice::Create
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
HALDevice* HALDevice::Create(
    const HwModule* pHwModule,
    UINT32          cameraId,
    UINT32          frameworkId)
{
    CamxResult result     = CamxResultENoMemory;
    HALDevice* pHALDevice = CAMX_NEW HALDevice;

    if (NULL != pHALDevice)
    {
        pHALDevice->m_fwId = frameworkId;

        result = pHALDevice->Initialize(pHwModule, cameraId);

        if (CamxResultSuccess != result)
        {
            pHALDevice->Destroy();

            pHALDevice = NULL;
        }
    }

    return pHALDevice;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// HALDevice::Destroy
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
VOID HALDevice::Destroy()
{
    if (NULL != m_pHALSession)
    {
        /// @todo (CAMX-1797) Remove this
        m_pHALSession = NULL;

        DestroyPipelines();
    }

    if (NULL != m_ppHAL3Streams)
    {
        for (UINT32 stream = 0; stream < m_numStreams; stream++)
        {
            if (NULL != m_ppHAL3Streams[stream])
            {
                CAMX_DELETE m_ppHAL3Streams[stream];
                m_ppHAL3Streams[stream] = NULL;
            }
        }

        CAMX_FREE(m_ppHAL3Streams);
        m_ppHAL3Streams = NULL;
    }

    CAMX_DELETE this;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// HALDevice::DestroyPipelines
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
VOID HALDevice::DestroyPipelines()
{
    m_numPipelines = 0;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// HALDevice::Initialize
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
CamxResult HALDevice::Initialize(
    const HwModule* pHwModule,
    UINT32          cameraId)
{
    CamxResult result = CamxResultSuccess;

    m_cameraId = cameraId;

    if (CamxResultSuccess == result)
    {
        m_camera3Device.hwDevice.tag     = HARDWARE_DEVICE_TAG; /// @todo (CAMX-351) Get from local macro
        m_camera3Device.hwDevice.version = CAMERA_DEVICE_API_VERSION_3_3;
        m_camera3Device.hwDevice.close   = reinterpret_cast<CloseFunc>(GetHwDeviceCloseFunc());
        m_camera3Device.pDeviceOps       = reinterpret_cast<Camera3DeviceOps*>(GetCamera3DeviceOps());
        m_camera3Device.pPrivateData     = this;
        // NOWHINE CP036a: Need exception here
        m_camera3Device.hwDevice.pModule = const_cast<HwModule*>(pHwModule);

        m_HALCallbacks.ProcessCaptureResult = ProcessCaptureResult;
        m_HALCallbacks.NotifyResult         = Notify;
        CamX::ChiOverrideBypass(&m_HALCallbacks);
    }

    m_pHALSession = NULL;
    Utils::Memset(m_flushRequest, 0, sizeof(m_flushRequest));

    return result;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// HALDevice::ProcessCaptureResult
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
VOID HALDevice::ProcessCaptureResult(
    const Camera3Device*        pCamera3Device,
    const Camera3CaptureResult* pCamera3CaptureResult)
{
    // 获取HALDevice指针
    HALDevice*              pHALDevice              = static_cast<HALDevice*>(pCamera3Device->pPrivateData);
    // 定义局部变量
    Camera3NotifyMessage    camera3NotifyMessage    = {};
    BOOL                    sendBufferNotify        = FALSE;

    // 若pCamera3CaptureResult的输出缓存数 > 0
    // 初始化pCamera3CaptureResult->pOutputBuffers的每个元素的releaseFence变量并打印每个输出缓存的流
    if (pCamera3CaptureResult->numOutputBuffers> 0)
    {
        for (UINT i = 0; i < pCamera3CaptureResult->numOutputBuffers; i++)
        {
            Camera3StreamBuffer* pStreamBuffer =
                // NOWHINE CP036a: Google API requires const type
                const_cast<Camera3StreamBuffer*>(&pCamera3CaptureResult->pOutputBuffers[i]);
            // 此缓冲区的释放同步围栏的句柄。当将缓冲区返回到框架时，HAL必须设置这个围栏，或者写-1来表示不需要等待这个缓冲区。
            pStreamBuffer->releaseFence = -1;
            CAMX_LOG_INFO(CamxLogGroupHAL,
                          "Returning framework result Frame: %d, Metadata: %p, Stream %p, Fmt: %d Width: %d Height: %d",
                          pCamera3CaptureResult->frameworkFrameNum,
                          pCamera3CaptureResult->pResultMetadata,
                          pCamera3CaptureResult->pOutputBuffers[i].pStream,
                          pCamera3CaptureResult->pOutputBuffers[i].pStream->format,
                          pCamera3CaptureResult->pOutputBuffers[i].pStream->width,
                          pCamera3CaptureResult->pOutputBuffers[i].pStream->height,
                          pCamera3CaptureResult->pOutputBuffers[i].releaseFence,
                          pCamera3CaptureResult->pOutputBuffers[i].bufferStatus);

            // 如果启用了刷新
            if (TRUE == pHALDevice->IsFlushEnabled())
            {
                // 如果存在pCamera3CaptureResult->pOutputBuffers的某个元素的缓存状态OK
                if (pCamera3CaptureResult->pOutputBuffers[i].bufferStatus == 0)
                {
                    sendBufferNotify = TRUE;
                    Camera3CaptureResult* pStreamResult =
                    // NOWHINE CP036a: Google API requires const type
                        const_cast<Camera3CaptureResult*>(pCamera3CaptureResult);
                    // 部分元数据结果的数量设置为1
                    pStreamResult->numPartialMetadata = 1;
                    // 改变bufferStatus
                    pStreamBuffer->bufferStatus = BufferStatusError;
                    pStreamBuffer->releaseFence = -1;
                }
            }
        }
    }
    else if (NULL != pCamera3CaptureResult->pResultMetadata)
    {
        CAMX_LOG_VERBOSE(CamxLogGroupHAL,
                      "Returning framework result metadata only for frame: %d, Metadata: %p",
                      pCamera3CaptureResult->frameworkFrameNum, pCamera3CaptureResult->pResultMetadata);
    }

    // 如果启用了刷新且存在pCamera3CaptureResult->pOutputBuffers的某元素的缓存状态都OK
    if (TRUE == sendBufferNotify)
    {
        // 初始化camera3NotifyMessage
        Utils::Memset(&camera3NotifyMessage, 0, sizeof(camera3NotifyMessage));
        // 初始化camera3NotifyMessage
        camera3NotifyMessage.messageType = MessageTypeError;
        camera3NotifyMessage.message.errorMessage.errorMessageCode = MessageCodeRequest;
        camera3NotifyMessage.message.errorMessage.frameworkFrameNum = pCamera3CaptureResult->frameworkFrameNum;
        camera3NotifyMessage.message.errorMessage.pErrorStream = NULL;
        CAMX_LOG_VERBOSE(CamxLogGroupCore,
            "Notify frame num %d, from Hal with error", pCamera3CaptureResult->frameworkFrameNum);
        pHALDevice->GetCallbackOps()->Notify(pHALDevice->GetCallbackOps(), &camera3NotifyMessage);
    }

    pHALDevice->GetCallbackOps()->ProcessCaptureResult(pHALDevice->GetCallbackOps(), pCamera3CaptureResult);
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// HALDevice::Notify
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
VOID HALDevice::Notify(
    const Camera3Device*        pCamera3Device,
    const Camera3NotifyMessage* pCamera3NotifyMessage)
{
    HALDevice* pHALDevice = static_cast<HALDevice*>(pCamera3Device->pPrivateData);

    UINT32 previewMappingIndex = 0;
    if (MessageTypeShutter == pCamera3NotifyMessage->messageType)
    {
        previewMappingIndex = pCamera3NotifyMessage->message.shutterMessage.frameworkFrameNum % MaxOutstandingRequests;
    }
    else if (MessageTypeError == pCamera3NotifyMessage->messageType)
    {
        previewMappingIndex = pCamera3NotifyMessage->message.errorMessage.frameworkFrameNum % MaxOutstandingRequests;
    }

    if (MessageTypeShutter == pCamera3NotifyMessage->messageType)
    {
        CAMX_LOG_VERBOSE(CamxLogGroupCore, "Setting before notify error %d and mapping index = %d",
                pCamera3NotifyMessage->message.errorMessage.frameworkFrameNum,
                pHALDevice->m_flushRequest[previewMappingIndex]);
    }
    else
    {
        CAMX_LOG_VERBOSE(CamxLogGroupCore, "Setting before notify error %d index = %d",
                pCamera3NotifyMessage->message.errorMessage.frameworkFrameNum,
                pHALDevice->m_flushRequest[previewMappingIndex]);
    }

    if ((0 == pHALDevice->m_flushRequest[previewMappingIndex]) &&
        (TRUE == pHALDevice->m_bFlushEnabled))
    {
        CAMX_LOG_VERBOSE(CamxLogGroupCore, "notify previewMappingIndex %d, msg type %d",
            previewMappingIndex,
            pCamera3NotifyMessage->messageType);
        if (MessageTypeError == pCamera3NotifyMessage->messageType)
        {
            if (pCamera3NotifyMessage->message.errorMessage.errorMessageCode == MessageCodeRequest)
            {
                CAMX_LOG_INFO(CamxLogGroupCore, "Setting notify error");
                pHALDevice->m_flushRequest[previewMappingIndex] = 1;
            }
        }
        pHALDevice->GetCallbackOps()->Notify(pHALDevice->GetCallbackOps(), pCamera3NotifyMessage);
    }
    else
    {
        pHALDevice->GetCallbackOps()->Notify(pHALDevice->GetCallbackOps(), pCamera3NotifyMessage);
    }
}

/*
    首先获取闪光灯硬件信息，若操作模式为受限高速，那么芯片集支持的能力中有受限高速视频
    如果pStreamConfigs->operationMode不为受限高速，查询流配置的角度是否有效并统计输入输出流的个数
    如果硬件环境中多相机VR功能被使能了或者多相机被使能了，则检查获取到的相机是否支持流的分辨率
    遍历硬件环境的流配置，如果传入流的配置与硬件环境的流配置匹配，如果流类型相同，判断可用流为true，否则，如果传入的流配置为双向的，并且硬件环境中的流配置类型为输入或输出，如果硬件环境中有两个输入流或输出流，判断可用流为true
    如果内部像素流格式与传入的流格式相同，则判断有可用流
    如果没有可用流，传感器有Quad CFA模式且不暴露全尺寸给QCFA，若为输出流、传入的流宽高都小于Quad CFA传感器的四分之一大小，则判断有可用流
    如果还是不匹配，则说明配流失败，修改返回值，打印日志
*/
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// HALDevice::CheckValidStreamConfig
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/*
    struct Camera3StreamConfig
    {
        UINT32                  numStreams;     ///< The total number of input and output streams in the streams list.
                                                ///  There must be at least one output-capable stream.
        Camera3Stream**         ppStreams;      ///< An array of camera stream pointers, defining the input/output
                                                ///  configuration for the camera HAL device.
        Camera3StreamConfigMode operationMode;  ///< The operation mode of streams in this configuration
    #if defined(CAMX_ANDROID_API) && (CAMX_ANDROID_API >= 28) //Android-P or better
        CameraMetadata*         pSessionParameters;    ///< Session metadata buffer
    #endif
    };
*/
CamxResult HALDevice::CheckValidStreamConfig(
    Camera3StreamConfig* pStreamConfigs
    ) const
{
    // 定义返回值
    CamxResult              result           = CamxResultSuccess;
    // 输出流个数
    UINT32                  numOutputStreams = 0;
    // 输入流个数
    UINT32                  numInputStreams  = 0;
    // 获取HwEnvironment实例
    const HwEnvironment*    pHWEnvironment   = HwEnvironment::GetInstance();
    // 临时变量用于传指针，获取相机硬件信息
    HwCameraInfo            cameraInfo;
    // 获取StaticSettings实例
    const StaticSettings*   pSettings        = HwEnvironment::GetInstance()->GetStaticSettings();

    // 获取闪光灯的逻辑ID
    UINT32 logicalCameraId =
               HAL3Module::GetInstance()->GetCHIAppCallbacks()->CHIRemapCameraId(m_fwId,
                                                                                IdRemapTorch);
    // 传感器模块的静态能力
    const SensorModuleStaticCaps* pSensorCaps = NULL;

    // GetCameraInfo: 根据roll、pitch、yaw的不同情况给指针赋值并初始化传入参数的指针变量
    // 通过传入闪光灯id与cameraInfo指针，获取相机硬件信息，即闪光灯硬件信息
    result = pHWEnvironment->GetCameraInfo(logicalCameraId, &cameraInfo);

    if (CamxResultSuccess == result)
    {
        // 从相机硬件信息中取出传感器静态能力
        pSensorCaps = cameraInfo.pSensorCaps;

        // 如果传入的想要配置的流的操作模式为受限高速
        // StreamConfigModeConstrainedHighSpeed: 用于支持高速捕获（high-speed capture）功能
        if (StreamConfigModeConstrainedHighSpeed == pStreamConfigs->operationMode)
        {
            // 是否支持受限高速
            BOOL isConstrainedHighSpeedSupported = FALSE;

            // 遍历相机信息中芯片可以被请求的能力
            for (UINT i = 0; i < cameraInfo.pPlatformCaps->numRequestCaps; i++)
            {
                // 如果芯片可以被请求的能力中有受限高速视频
                if (RequestAvailableCapabilitiesConstrainedHighSpeedVideo == cameraInfo.pPlatformCaps->requestCaps[i])
                {
                    // 设为true
                    isConstrainedHighSpeedSupported = TRUE;
                    break;
                }
            }

            if (FALSE == isConstrainedHighSpeedSupported)
            {
                // 芯片可以被请求的能力中没有受限高速视频
                result = CamxResultEInvalidArg;
                CAMX_LOG_ERROR(CamxLogGroupHAL, "Invalid operationMode: %d", pStreamConfigs->operationMode);
            }
        }
    }
    
    // 如果pStreamConfigs->operationMode不为受限高速 || 若为受限高速，那么芯片集支持的能力中有受限高速视频
    if (CamxResultSuccess == result)
    {
        // 相机硬件信息中取出硬件环境的能力，这些能力支持配置的流数量
        const UINT                  numAvailableConfigs     = cameraInfo.pHwEnvironmentCaps->numStreamConfigs;
        // 相机硬件信息中取出硬件环境的能力，这些能力支持的流的一系列配置
        const ScalerStreamConfig*   pAvailableConfigs       = cameraInfo.pHwEnvironmentCaps->streamConfigs;
        // 芯片支持的能力中，支持的内部HAL像素格式的数量
        const UINT                  numInternalPixelFormat  = cameraInfo.pPlatformCaps->numInternalPixelFormats;
        // 支持的内部HAL像素格式
        const HALPixelFormat*       pInternalFormats        = cameraInfo.pPlatformCaps->internalPixelFormats;
        // 是否有可获取的流
        BOOL                        isAvailableStream;
        // 匹配的输入输出配置的数量
        UINT                        numMatchedInputOutputConfigs;

        // Count the number of input and output streams
        // 遍历流配置
        for (UINT32 stream = 0; stream < pStreamConfigs->numStreams; stream++)
        {
            // 初始化
            isAvailableStream               = FALSE;
            numMatchedInputOutputConfigs    = 0;

            // Check if the stream has a valid rotation
            // 除了0、90、180、270，其余角度都为无效角度
            // 为了简化流配置并确保最佳性能和兼容性，通常只允许使用0、90、180和270度的角度。
            // 这些角度可以满足大多数应用场景的需求，并且与设备的方向和常见的使用方式相匹配。
            if ((pStreamConfigs->ppStreams[stream]->rotation != StreamRotationCCW0)   &&
                (pStreamConfigs->ppStreams[stream]->rotation != StreamRotationCCW90)  &&
                (pStreamConfigs->ppStreams[stream]->rotation != StreamRotationCCW180) &&
                (pStreamConfigs->ppStreams[stream]->rotation != StreamRotationCCW270))
            {
                result = CamxResultEInvalidArg;
                CAMX_LOG_ERROR(CamxLogGroupHAL,
                    "Stream has an invalid rotation: %d",
                    pStreamConfigs->ppStreams[stream]->rotation);
                break;
            }

            // 传入的参数pStreamConfigs中的每个流的流类型
            switch (pStreamConfigs->ppStreams[stream]->streamType)
            {
                // 输出流
                case StreamTypeOutput:
                    numOutputStreams++;
                    break;

                // 输入流
                case StreamTypeInput:
                    numInputStreams++;
                    break;

                // 双向输入输出流
                case StreamTypeBidirectional:
                    numOutputStreams++;
                    numInputStreams++;
                    break;

                default:
                    CAMX_ASSERT_ALWAYS_MESSAGE("Invalid streamStype: %d", pStreamConfigs->ppStreams[stream]->streamType);
                    result = CamxResultEInvalidArg;
                    break;
            }

            // Check if device support the stream configuration.
            // 如果硬件环境中多相机VR功能被使能了或者多相机被使能了
            if ((TRUE == pSettings->multiCameraVREnable) || (TRUE == pSettings->multiCameraEnable))
            {
                // 获取相机的逻辑ID
                logicalCameraId =
                HAL3Module::GetInstance()->GetCHIAppCallbacks()->CHIRemapCameraId(m_fwId, IdRemapCamera);
                // 首先获取元数据，然后遍历元数据的数组，检查方法传入的流与元数据中的有多少个匹配，根据流类型与匹配数返回bool
                // 检查获取到的相机是否支持流的分辨率
                isAvailableStream = CheckSupportedResolution(logicalCameraId, pStreamConfigs->ppStreams[stream]->format,
                                   pStreamConfigs->ppStreams[stream]->width , pStreamConfigs->ppStreams[stream]->height ,
                                   pStreamConfigs->ppStreams[stream]->streamType);
            }
            else
            {
                for (UINT32 i = 0; i < numAvailableConfigs; i++)
                {
                    // 遍历硬件环境的流配置，如果传入流的配置与硬件环境的流配置匹配
                    if ((pStreamConfigs->ppStreams[stream]->format == pAvailableConfigs[i].format) &&
                        (pStreamConfigs->ppStreams[stream]->width  == pAvailableConfigs[i].width) &&
                        (pStreamConfigs->ppStreams[stream]->height == pAvailableConfigs[i].height))
                    {
                        // 如果流类型相同，判断可用流为true
                        if (pStreamConfigs->ppStreams[stream]->streamType == pAvailableConfigs[i].type)
                        {
                            isAvailableStream = TRUE;
                            break;
                        }
                        // 否则，如果传入的流配置为双向的，并且硬件环境中的流配置类型为输入或输出
                        else if ((StreamTypeBidirectional == pStreamConfigs->ppStreams[stream]->streamType) &&
                                 ((ScalerAvailableStreamConfigurationsOutput == pAvailableConfigs[i].type) ||
                                 (ScalerAvailableStreamConfigurationsInput  == pAvailableConfigs[i].type)))
                        {
                                 // For StreamTypeBidirectional, both input and output stream configuration need to be supported
                                 // by device.
                            numMatchedInputOutputConfigs++;
                            // 如果硬件环境中有两个输入流或输出流，判断可用流为true
                            if (ScalerAvailableStreamConfigurationsEnd == numMatchedInputOutputConfigs)
                            {
                                isAvailableStream = TRUE;
                                break;
                            }
                        }
                    }
                }
            }
            // 如果传入的流配置都与硬件环境中不匹配，那么检查硬件环境支持的内部HAL像素流配置
            // Check if driver allow non-standard Android scaler stream format. e.g. HALPixelFormatY8
            if ((FALSE == isAvailableStream) && (TRUE == pSettings->enableInternalHALPixelStreamConfig))
            {
                for (UINT32 i = 0; i < numInternalPixelFormat; i++)
                {
                    // 如果内部像素流格式与传入的流格式相同，则判断有可用流
                    if (pStreamConfigs->ppStreams[stream]->format == pInternalFormats[i])
                    {
                        isAvailableStream = TRUE;
                        break;
                    }
                }
            }

            // 对于Quad CFA传感器，如果只暴露四分之一的大小给所有的app，则OEM app 仍会配置全尺寸快照
            // For Quad CFA sensor, if only expose quarter size to all apps (OEM app, 3rd app or CTS),
            // but OEM app will still config full size snapshot, need to accept it.

            // 如果没有可用流，传感器有Quad CFA模式且不暴露全尺寸给QCFA
            if ((FALSE == isAvailableStream) &&
                (TRUE  == pSensorCaps->isQuadCFASensor) &&
                (FALSE == pSettings->exposeFullSizeForQCFA))
            {
                // 若为输出流、传入的流宽高都小于Quad CFA传感器的尺寸，则判断有可用流
                if ((StreamTypeOutput == pStreamConfigs->ppStreams[stream]->streamType) &&
                    (pStreamConfigs->ppStreams[stream]->width  <= static_cast<UINT32>(pSensorCaps->QuadCFADim.width)) &&
                    (pStreamConfigs->ppStreams[stream]->height <= static_cast<UINT32>(pSensorCaps->QuadCFADim.height)))
                {
                    CAMX_LOG_INFO(CamxLogGroupHAL,
                                   "Accept size (%d x %d) for Quad CFA sensor",
                                   pStreamConfigs->ppStreams[stream]->width,
                                   pStreamConfigs->ppStreams[stream]->height);

                    isAvailableStream = TRUE;
                }
            }

            // 如果还是不匹配，则说明配流失败，修改返回值，打印日志
            if (FALSE == isAvailableStream)
            {
                result = CamxResultEInvalidArg;
                CAMX_LOG_ERROR(CamxLogGroupHAL,
                               "Invalid streamStype: %d, format: %d, width: %d, height: %d",
                               pStreamConfigs->ppStreams[stream]->streamType,
                               pStreamConfigs->ppStreams[stream]->format,
                               pStreamConfigs->ppStreams[stream]->width,
                               pStreamConfigs->ppStreams[stream]->height);
                break;
            }
        }
    }

    if (CamxResultSuccess == result)
    {
        // We allow 0 up to MaxNumOutputBuffers output streams. Zero output streams are allowed, despite the HAL3 specification,
        // in order to support metadata-only requests.
        if (numOutputStreams > MaxNumOutputBuffers)
        {
            CAMX_LOG_ERROR(CamxLogGroupHAL,
                           "Invalid number of output streams (including bi-directional): %d",
                           numOutputStreams);
            result = CamxResultEInvalidArg;
        }

        // We allow 0 up to MaxNumInputBuffers input streams
        if (numInputStreams > MaxNumInputBuffers)
        {
            CAMX_LOG_ERROR(CamxLogGroupHAL,
                           "Invalid number of input streams (including bi-directional): %d",
                           numInputStreams);
            result = CamxResultEInvalidArg;
        }
    }
    return result;
}

/*
    首先获取元数据，然后遍历元数据的数组，检查方法传入的流与元数据中的有多少个匹配，根据流类型与匹配数返回bool
*/
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// HALDevice::CheckSupportedResolution
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
BOOL HALDevice::CheckSupportedResolution(
    INT32 cameraId,
    INT32 format,
    UINT32 width,
    UINT32 height,
    INT32 streamType
    ) const
{
    CameraInfo info;
    // 获取相机硬件信息
    if (0 != HAL3Module::GetInstance()->GetCHIAppCallbacks()->CHIGetCameraInfo(cameraId, &info))
    {
        CAMX_LOG_INFO(CamxLogGroupHAL, "Can't get camera info for camera id: %d", cameraId);
        return FALSE;
    }
    // 根据静态相机信息以及可用流配置标记获取元数据
    // NOWHINE CP036a: The 'getters' for metadata because of being a sorted hashmap can modify the object
    Metadata* pStaticCameraInfo = const_cast<Metadata*>(info.pStaticCameraInfo);
    INT32* pAvailStreamConfig   = NULL;
    // &pAvailStreamConfig是为了给指针的内容赋值
    INT32 val = HAL3MetadataUtil::GetMetadata(pStaticCameraInfo, ScalerAvailableStreamConfigurations,
            reinterpret_cast<VOID**>(&pAvailStreamConfig));

    // 如果获取元数据失败
    if (val != CamxResultSuccess)
    {
        CAMX_LOG_INFO(CamxLogGroupHAL, "Can't find the metadata entry for ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS");
        return FALSE;
    }

    // 如果给指针赋值失败
    if (NULL == pAvailStreamConfig)
    {
        CAMX_LOG_INFO(CamxLogGroupHAL,
                      "Value of the metadata entry for ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS is NULL");
        return FALSE;
    }

    // 获取元数据有几个条目
    SIZE_T entryCount = HAL3MetadataUtil::GetMetadataEntryCount(pStaticCameraInfo);

    INT32 matched = 0;

    // 如果流不为双向流
    if (streamType != StreamTypeBidirectional)
    {
        // 根据情况给流类型赋值
        streamType = (streamType == StreamTypeOutput ? ScalerAvailableStreamConfigurationsOutput :
            (streamType == StreamTypeInput ? ScalerAvailableStreamConfigurationsInput : -1));

        // 如果不是输入流或输出流
        if (-1 == streamType)
        {
            CAMX_LOG_INFO(CamxLogGroupHAL, "Invalid stream direction: %d", streamType);
            return FALSE;
        }
    }

    // 定义数据元素偏移量
    const INT32 STREAM_WIDTH_OFFSET       = 1;
    const INT32 STREAM_HEIGHT_OFFSET      = 2;
    const INT32 STREAM_IS_INPUT_OFFSET    = 3;
    const INT32 STREAM_CONFIGURATION_SIZE = 4;

    // 遍历获取到的元数据
    for (UINT32 i = 0; i < entryCount; i += STREAM_CONFIGURATION_SIZE)
    {
        /* This is a special case because, for bi-directional stream we need to ensure
         * given resolution is supported both as input and output */
        
        // 取出元数据
        INT32 queriedFormat    = pAvailStreamConfig[i];
        UINT32 swidth          = pAvailStreamConfig[i + STREAM_WIDTH_OFFSET];
        UINT32 sheight         = pAvailStreamConfig[i + STREAM_HEIGHT_OFFSET];
        INT32 streamDirection  = pAvailStreamConfig[i + STREAM_IS_INPUT_OFFSET];

        // 如果为双向流类型
        if (StreamTypeBidirectional == streamType)
        {
            // 如果流方向为输出流方向并且元数据查询到的格式与方法传入的格式相同
            if ((ScalerAvailableStreamConfigurationsOutput == streamDirection) &&
                (format == queriedFormat))
            {
                // 如果元数据与传入的宽高也一致，那么判断为匹配
                if (swidth == width &&
                    sheight == height)
                {
                    matched++;
                }
            }
            // 如果流方向为输入流方向
            if ((ScalerAvailableStreamConfigurationsInput == streamDirection) &&
                (format == queriedFormat))
            {
                if (swidth == width &&
                    sheight == height)
                {
                    matched++;
                }
            }
        }
        else
        {
            // 若为单输入或单输出流，若流类型与元数据获取到的流类型一致，且格式、宽高也一致，则判断为匹配
            if (streamDirection == streamType && format == queriedFormat)
            {
                if (swidth == width &&
                    sheight == height)
                {
                    matched++;
                }
            }
        }
    }

    // 如果流类型为双向流，且有两个匹配，返回false；若只有一个匹配，则返回true
    if ((StreamTypeBidirectional == streamType) && (matched == 2))
    {
        return FALSE;
    }
    // 如果流类型为输入或输出流，且只有一个元数据流与传入的流匹配，则返回true；若有多个匹配，也返回true
    if ((StreamTypeBidirectional != streamType) && (matched == 1))
    {
        return TRUE;
    }
    return TRUE;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// HALDevice::InitializeHAL3Streams
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
CamxResult HALDevice::InitializeHAL3Streams(
    Camera3StreamConfig* pStreamConfigs)
{
    CamxResult   result        = CamxResultSuccess;
    UINT32       stream        = 0;
    HAL3Stream*  pHAL3Stream   = NULL;
    HAL3Stream** ppHAL3Streams = NULL;

    ppHAL3Streams = static_cast<HAL3Stream**>(CAMX_CALLOC(sizeof(HAL3Stream*) * MaxNumOutputBuffers));

    if (NULL != ppHAL3Streams)
    {
        // Reset the existing list of streams, if any. This is done before checking to see if the stream can be reused since
        // the existing stream's flag will be updated directly.
        if (NULL != m_ppHAL3Streams)
        {
            for (stream = 0; (stream < MaxNumOutputBuffers) && (NULL != m_ppHAL3Streams[stream]); stream++)
            {
                m_ppHAL3Streams[stream]->SetStreamReused(FALSE);
            }
        }

        // For each incoming stream, check whether it matches an existing configuration that can be reused or if it is a new
        // configuration.
        for (stream = 0; stream < pStreamConfigs->numStreams; stream++)
        {
            CAMX_ENTRYEXIT_SCOPE_ID(CamxLogGroupHAL, SCOPEEventHAL3DeviceInitializeHAL3Stream, stream);

            Camera3Stream* pStream = pStreamConfigs->ppStreams[stream];

            // If the maximum number of inflight buffers allowed by this stream is > 0, we know the HAL has already seen this
            // stream configuration before since the buffer count comes from the HAL. Therefore, attempt to reuse it. If the
            // maximum number of buffers is 0, create a new HAL3 stream object.
            if ((pStream->maxNumBuffers > 0) && (TRUE == AllowStreamReuse))
            {
                pHAL3Stream = reinterpret_cast<HAL3Stream*>(pStream->pPrivateInfo);

                if ((NULL != pHAL3Stream) && (TRUE == pHAL3Stream->IsStreamConfigMatch(pStream)))
                {
                    pHAL3Stream->SetStreamReused(TRUE);
                    pHAL3Stream->SetStreamIndex(stream);
                    ppHAL3Streams[stream] = pHAL3Stream;
                }
                else
                {
                    CAMX_LOG_ERROR(CamxLogGroupHAL, "Invalid stream configuration!");
                    // HAL interface requires -EINVAL (EInvalidArg) for invalid arguments
                    result = CamxResultEInvalidArg;
                    ppHAL3Streams[stream] = NULL;
                    break;
                }
            }
            else
            {
                pHAL3Stream = CAMX_NEW HAL3Stream(pStream, stream, Format::RawMIPI);

                if (NULL != pHAL3Stream)
                {
                    ppHAL3Streams[stream] = pHAL3Stream;
                    pStream->pPrivateInfo = pHAL3Stream;
                }
                else
                {
                    CAMX_LOG_ERROR(CamxLogGroupHAL, "Cannot create HAL3Stream! Out of memory!");

                    result = CamxResultENoMemory;
                    ppHAL3Streams[stream] = NULL;
                    break;
                }
            }
        }

        // If stream reuse and creation successful, store configurations in m_ppHAL3Streams, otherwise clean up
        if (CamxResultSuccess == result)
        {
            DestroyUnusedStreams(m_ppHAL3Streams, m_numStreams);

            m_ppHAL3Streams = ppHAL3Streams;
            m_numStreams    = pStreamConfigs->numStreams;
        }
        else
        {
            DestroyUnusedStreams(ppHAL3Streams, pStreamConfigs->numStreams);
            ppHAL3Streams = NULL;
        }
    }
    else
    {
        CAMX_LOG_ERROR(CamxLogGroupHAL, "Creating ppHAL3Streams failed! Out of memory!");
        result = CamxResultENoMemory;
    }

    return result;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// HALDevice::DestroyUnusedStreams
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void HALDevice::DestroyUnusedStreams(
    HAL3Stream** ppHAL3Streams,
    UINT32       numStreams
    ) const
{
    if (NULL != ppHAL3Streams)
    {
        for (UINT32 stream = 0; stream < numStreams; stream++)
        {
            if ((NULL != ppHAL3Streams[stream]) && (FALSE == ppHAL3Streams[stream]->IsStreamReused()))
            {
                CAMX_DELETE ppHAL3Streams[stream];
                ppHAL3Streams[stream] = NULL;
            }
        }

        CAMX_FREE(ppHAL3Streams);
        ppHAL3Streams = NULL;
    }
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// HALDevice::ConfigureStreams
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
CamxResult HALDevice::ConfigureStreams(
    Camera3StreamConfig* pStreamConfigs)
{
    CamxResult result                     = CamxResultSuccess;

    // Validate the incoming stream configurations
    /*
        首先获取闪光灯硬件信息，若操作模式为受限高速，那么检查芯片集支持的能力中是否有受限高速视频
        如果pStreamConfigs->operationMode不为受限高速，查询流配置的角度是否有效并统计输入输出流的个数
        如果硬件环境中多相机VR功能被使能了或者多相机被使能了，则检查获取到的相机是否支持流的分辨率
        遍历硬件环境的流配置，如果传入流的配置与硬件环境的流配置匹配，如果流类型相同，判断可用流为true，
        否则，如果传入的流配置为双向的，并且硬件环境中的流配置类型为输入或输出，如果硬件环境中有两个输入流或输出流，判断可用流为true
        如果内部像素流格式与传入的流格式相同，则判断有可用流
        如果没有可用流，传感器有Quad CFA模式且不暴露全尺寸给QCFA，若为输出流、传入的流宽高都小于Quad CFA传感器的四分之一大小，则判断有可用流
        如果还是不匹配，则说明配流失败，修改返回值，打印日志
    */
    // 检查是否有可用流
    result = CheckValidStreamConfig(pStreamConfigs);

    // 如果流配置的操作模式为受限高速
    if (StreamConfigModeConstrainedHighSpeed == pStreamConfigs->operationMode)
    {
        // 在传入的流配置中寻找第一个输出流，缓存宽高，在芯片集中寻找与其宽高一致的HFR视频流，并选择第一个视频流的batchSize和fps
        SearchNumBatchedFrames (pStreamConfigs, &m_usecaseNumBatchedFrames, &m_FPSValue);
        CAMX_ASSERT(m_usecaseNumBatchedFrames > 1);
    }
    else
    {
        // Not a HFR usecase batch frames value need to set to 1.
        // 如果不是HFR，usecase batch frames value需要被设置为1
        m_usecaseNumBatchedFrames = 1;
    }

    // 如果硬件环境中有可用流
    if (CamxResultSuccess == result)
    {
        // 初始化pipeline的数量
        m_numPipelines = 0;

        // CHI extension module enabled
        // 如果camera hardware interface插件模块被使能了
        if (TRUE == m_CHIOverrideEnabled)
        {
            /// @todo (CAMX-1797) Need to find a proper way to handle this
            /*
                首先获取logicalCameraId，销毁m_pSelectedUsecase[logicalCameraId]、m_pStreamConfig[logicalCameraId]->streams、
                m_pStreamConfig[logicalCameraId]、m_pPerfLockManager[logicalCameraId];
                取消绑定m_logicalCameraInfo[logicalCameraId].m_pCamera3Device、m_pCameraDeviceInfo[logicalCameraId].m_pCamera3Device、
                m_pStreamConfig[logicalCameraId]->streams、m_pStreamConfig[logicalCameraId]
            */
            // 通过m_camera3Device获取logical_camera_id，将use case、流配置销毁，相机指针置null
            HAL3Module::GetInstance()->GetCHIAppCallbacks()->CHITeardownOverrideSession(&m_camera3Device, 0, NULL);
        }
        
        // 查询CHI模块是否被覆盖
        m_CHIOverrideEnabled = QueryCHIModuleOverride(pStreamConfigs);

        // 覆盖失败
        if (FALSE == m_CHIOverrideEnabled)
        {
            CAMX_LOG_ERROR(CamxLogGroupHAL, "CHI Module did not override configure streams - this cannot be!");
            result = CamxResultEFailed;
        }
        // 覆盖成功
        else
        {
            CAMX_LOG_WARN(CamxLogGroupHAL, "CHI Module overriding configure streams ... CHI is in control!");
        }
    }

    return result;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// HALDevice::QueryCHIModuleOverride
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// 查询CHIModule是否被覆盖
BOOL HALDevice::QueryCHIModuleOverride( 
    Camera3StreamConfig* pStreamConfigs)
{
    BOOL isOverrideEnabled = FALSE;

    // 检查是否有CHI override module的句柄
    if (TRUE == HAL3Module::GetInstance()->IsCHIOverrideModulePresent())
    {
        // 获取CHI和APP侧的回调函数
        CHIAppCallbacks* pCHIAppCallbacks  = HAL3Module::GetInstance()->GetCHIAppCallbacks();

        /// @todo (CAMX-1518) Handle private data from Override module
        VOID* pPrivateData;

        pCHIAppCallbacks->CHIInitializeOverrideSession(GetCameraId(),
                                                       &m_camera3Device,
                                                       &m_HALCallbacks,
                                                       pStreamConfigs,
                                                       &isOverrideEnabled,
                                                       &pPrivateData);
    }

    return isOverrideEnabled;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// HALDevice::IsPipelineRealtime
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
BOOL HALDevice::IsPipelineRealtime(
    const PerPipelineInfo*  pPipelineInfo)
{
    BOOL isRealtimePipeline = TRUE;

    for (UINT i = 0; i < pPipelineInfo->numNodes; i++)
    {
        if ((1 == pPipelineInfo->nodeInfo[i].inputPorts.numPorts) &&
            (TRUE == pPipelineInfo->nodeInfo[i].inputPorts.portInfo[0].flags.isSourceBuffer))
        {
            isRealtimePipeline = FALSE;
            break;
        }
    }

    return isRealtimePipeline;
}

/*
    在传入的流配置中寻找第一个输出流，缓存宽高，在芯片集中寻找与其宽高一致的HFR视频流，并选择第一个视频流的batchSize和fps
*/
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// HALDevice::SearchNumBatchedFrames
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
VOID HALDevice::SearchNumBatchedFrames(
    Camera3StreamConfig* pStreamConfigs,
    UINT*                pBatchSize,
    UINT*                pFPSValue)
{
    // 缓存宽高
    INT32 width    = 0;
    INT32 height   = 0;

    // We will take the following steps -
    //  1) We will search SupportedHFRVideoSizes, for the matching Video/Preview stream.
    //     Note: For the use case of multiple output streams, application must select one unique size from this metadata
    //           to use (e.g., preview and recording streams must have the same size). Otherwise, the high speed capture
    //           session creation will fail
    //  2) If a single entry is found in SupportedHFRVideoSizes, we choose the batchsize from that entry
    //  3) Else (multiple entries are found), we see if PropertyIDUsecaseFPS is published
    //  4)  If published, we pick the batchsize from that entry which is closest to the published FPS
    //  5)  If not published, we pick the batchsize from the first entry

    // 遍历流配置中的流
    for (UINT streamIndex = 0 ; streamIndex < pStreamConfigs->numStreams; streamIndex++)
    {
        // 如果流类型为输出流
        if (StreamTypeOutput == pStreamConfigs->ppStreams[streamIndex]->streamType)
        {
            // 缓存该输出流的宽高
            width  = pStreamConfigs->ppStreams[streamIndex]->width;
            height = pStreamConfigs->ppStreams[streamIndex]->height;
            break;
        }
    }

    // 芯片集的能力
    const PlatformStaticCaps*       pCaps                     =
        HwEnvironment::GetInstance()->GetPlatformStaticCaps();

    // 初始化HFRConfigurationParams指针数组pHFRParams
    const HFRConfigurationParams*   pHFRParams[MaxHFRConfigs] = { NULL };
    // 定义HFR入口的数量
    UINT                            numHFREntries             = 0;

    if ((0 != width) && (0 != height))
    {
        // 遍历芯片集支持的HFR视频的宽高
        for (UINT i = 0; i < pCaps->numDefaultHFRVideoSizes; i++)
        {
            // 如果视频流的宽高与缓存流的宽高一致
            if ((pCaps->defaultHFRVideoSizes[i].width == width) && (pCaps->defaultHFRVideoSizes[i].height == height))
            {
                // 存储第二个条目，索引+=2

                // Out of the pair of entries in the table, we would like to store the second entry
                pHFRParams[numHFREntries++] = &pCaps->defaultHFRVideoSizes[i + 1];
                // Make sure that we don't hit the other entry in the pair, again
                i++;
            }
        }

        // 如果有HFR入口，则选择第一个获取batchSize和fps
        if (numHFREntries >= 1)
        {
            *pBatchSize = pHFRParams[0]->batchSizeMax;
            *pFPSValue = pHFRParams[0]->maxFPS;
        }
        else
        {
            CAMX_LOG_ERROR(CamxLogGroupHAL, "Failed to find supported HFR entry!");
        }
    }
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// HALDevice::Close
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
CamxResult HALDevice::Close()
{
    CamxResult result = CamxResultSuccess;

    if (TRUE == IsCHIModuleOverrideEnabled())
    {
        /// @todo (CAMX-1797) Need to find a proper way to handle this
        m_CHIOverrideEnabled = FALSE;
        HAL3Module::GetInstance()->GetCHIAppCallbacks()->CHITeardownOverrideSession(&m_camera3Device, 0, NULL);
    }

    // Move torch release to post Session Destroy as we might set error conditions accordingly.
    UINT32 logicalCameraId =
                HAL3Module::GetInstance()->GetCHIAppCallbacks()->CHIRemapCameraId(m_fwId, IdRemapTorch);
    HAL3Module::GetInstance()->ReleaseTorchForCamera(logicalCameraId, m_fwId);

    /// @todo (CAMX-1797) Add support for SetDebugBuffers(0);

    return result;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// HALDevice::CloseCachedSensorHandles
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void HALDevice::CloseCachedSensorHandles(
    UINT32 cameraID)
{

    CamxResult              result               = CamxResultEFailed;
    const HwEnvironment*    pHWEnvironment       = HwEnvironment::GetInstance();
    HwCameraInfo            cameraInfo;
    BOOL                    reset                = FALSE;
    SensorSubDevicesCache*  pSensorDevicesCache  = NULL;
    SensorSubDeviceHandles* pSensorDeviceHandles = NULL;

    CAMX_LOG_INFO(CamxLogGroupHAL, "Check for any opened cached devices that needs to be closed for camera %d", cameraID);

    Utils::Memset(&cameraInfo, 0, sizeof(cameraInfo));
    if (NULL != pHWEnvironment)
    {
        result = pHWEnvironment->GetCameraInfo(cameraID, &cameraInfo);
        if (CamxResultSuccess == result)
        {
            pSensorDevicesCache  =
                reinterpret_cast<SensorSubDevicesCache*>(cameraInfo.pSensorCaps->pSensorDeviceCache);

            pSensorDeviceHandles =
                reinterpret_cast<SensorSubDeviceHandles*>(cameraInfo.pSensorCaps->pSensorDeviceHandles);
        }
        else
        {
            CAMX_LOG_ERROR(CamxLogGroupHAL, "Failed to retrieve camera info");
        }
    }

    if ((NULL == pHWEnvironment)      || (CamxResultSuccess != result) ||
        (NULL == pSensorDevicesCache) || (NULL == pSensorDeviceHandles))
    {
        // Cannot release the opened and cached HW handles OR No handles cached to release
        // This is not a fatal error, if the handles or cache is null that indicates there is no
        // HW that was cached to begin with.
        // If the HW environment is NULL, we would probably crash much earlier than this point
        result = CamxResultEFailed;
    }

    if (CamxResultSuccess == result)
    {
        // Release Actuator
        SubDeviceProperty actuatorDevice = pSensorDeviceHandles->actuatorDevice;
        if (TRUE == actuatorDevice.isAcquired)
        {
            CAMX_LOG_INFO(CamxLogGroupHAL, "Release actuatorDevice handle %d", actuatorDevice.hDevice);
            CSLReleaseDevice(cameraInfo.pSensorCaps->pHwContext->GetCSLSession(), actuatorDevice.hDevice);
            reset = TRUE;
        }
        else
        {
            CAMX_LOG_VERBOSE(CamxLogGroupHAL, "actuatorDevice handle already released");
        }

        // Release CSIPHY
        SubDeviceProperty CSIPHYDevice = pSensorDeviceHandles->CSIPHYDevice;
        if (TRUE == CSIPHYDevice.isAcquired)
        {
            CAMX_LOG_INFO(CamxLogGroupHAL, "Release CSIPHYDevice handle %d", CSIPHYDevice.hDevice);
            CSLReleaseDevice(cameraInfo.pSensorCaps->pHwContext->GetCSLSession(), CSIPHYDevice.hDevice);
            reset = TRUE;
        }
        else
        {
            CAMX_LOG_VERBOSE(CamxLogGroupHAL, "CSIPHYDevice handle already released");
        }

        // Release OIS
        SubDeviceProperty oisDevice = pSensorDeviceHandles->oisDevice;
        if (TRUE == oisDevice.isAcquired)
        {
            CAMX_LOG_INFO(CamxLogGroupHAL, "Release oisDevice handle %d", oisDevice.hDevice);
            CSLReleaseDevice(cameraInfo.pSensorCaps->pHwContext->GetCSLSession(), oisDevice.hDevice);
            reset = TRUE;
        }
        else
        {
            CAMX_LOG_VERBOSE(CamxLogGroupHAL, "oisDevice handle already released");
        }

        // Release Flash
        SubDeviceProperty flashDevice = pSensorDeviceHandles->flashDevice;
        if (TRUE == flashDevice.isAcquired)
        {
            CAMX_LOG_INFO(CamxLogGroupHAL, "Release flashDevice handle %d", flashDevice.hDevice);
            CSLReleaseDevice(cameraInfo.pSensorCaps->pHwContext->GetCSLSession(), flashDevice.hDevice);
            reset = TRUE;
        }
        else
        {
            CAMX_LOG_VERBOSE(CamxLogGroupHAL, "flashDevice handle already released");
        }

        // Release Sensor
        SubDeviceProperty sensorDevice = pSensorDeviceHandles->sensorDevice;
        if (TRUE == sensorDevice.isAcquired)
        {
            CAMX_LOG_INFO(CamxLogGroupHAL, "Release sensorDevice handle %d", sensorDevice.hDevice);
            CSLReleaseDevice(cameraInfo.pSensorCaps->pHwContext->GetCSLSession(), sensorDevice.hDevice);
            reset = TRUE;
        }
        else
        {
            CAMX_LOG_VERBOSE(CamxLogGroupHAL, "sensorDevice handle already released");
        }

        // Logs to show if the check was successful
        if (TRUE == reset)
        {
            CAMX_LOG_INFO(CamxLogGroupHAL, "Clear HW Handle cache for camera %d", cameraID);
            pSensorDevicesCache->ClearCache(cameraID);
        }
        else
        {
            CAMX_LOG_INFO(CamxLogGroupHAL, "All sensor devices already released");
        }
    }
}


////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// HALDevice::ProcessCaptureRequest
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
CamxResult HALDevice::ProcessCaptureRequest(
    Camera3CaptureRequest* pRequest)
{
    CamxResult result = CamxResultEFailed;

    m_flushRequest[pRequest->frameworkFrameNum % MaxOutstandingRequests] = 0;
    if (TRUE == IsCHIModuleOverrideEnabled())
    {
        CAMX_LOG_INFO(CamxLogGroupHAL,
                      "CHIOverride: Original framework framenumber %d contains %d output buffers",
                      pRequest->frameworkFrameNum,
                      pRequest->numOutputBuffers);

        CHIAppCallbacks* pCHIAppCallbacks = HAL3Module::GetInstance()->GetCHIAppCallbacks();

        /// @todo (CAMX-1797) CHI-only, do we need to pass in the device or probably not required
        CAMX_LOG_WARN(CamxLogGroupHAL, "ChiOverrideProcessRequest ignoring CameraDevice and PrivateData.");
        result = pCHIAppCallbacks->CHIOverrideProcessRequest(&m_camera3Device, pRequest, NULL);
    }
    else
    {
        CAMX_LOG_ERROR(CamxLogGroupHAL, "CHIModuleOverride disabled, rejecting HAL request");
    }

    CAMX_ASSERT(CamxResultSuccess == result);

    return result;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// HALDevice::Dump
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
VOID HALDevice::Dump(
    INT fd
    ) const
{
    CAMX_UNREFERENCED_PARAM(fd);
    // nothing worth dumping in here at the moment
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// HALDevice::Flush
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
CamxResult HALDevice::Flush()
{
    CAMX_ENTRYEXIT(CamxLogGroupCore);
    CamxResult result = CamxResultEInvalidArg;

    CHIAppCallbacks* pCHIAppCallbacks = HAL3Module::GetInstance()->GetCHIAppCallbacks();
    m_bFlushEnabled = TRUE;

    if ((NULL != pCHIAppCallbacks) && (NULL != m_camera3Device.pDeviceOps))
    {
        result = pCHIAppCallbacks->CHIOverrideFlush(&m_camera3Device);
    }

    Utils::Memset(m_flushRequest, 0, sizeof(m_flushRequest));
    m_bFlushEnabled = FALSE;

    return result;
}

CAMX_NAMESPACE_END
